From 1bcc086e020e0a86ad99496120ea4b4c5f4ef870 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Tue, 25 Jul 2006 17:01:49 +0100 Subject: [PATCH] Fix Linux so that it does not set a timeout if there are no pending timers. Fix Xen so that it does not immediately fire a timer event if it sees a very long timeout -- sometimes this means that there are no pending timers. Signed-off-by: Keir Fraser --- .../arch/i386/kernel/time-xen.c | 21 ++++++++++++------- xen/common/schedule.c | 7 +++++-- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c b/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c index d21a9560b1..504d27d663 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c @@ -958,11 +958,17 @@ u64 jiffies_to_st(unsigned long j) do { seq = read_seqbegin(&xtime_lock); delta = j - jiffies; - /* NB. The next check can trigger in some wrap-around cases, - * but that's ok: we'll just end up with a shorter timeout. */ - if (delta < 1) - delta = 1; - st = processed_system_time + (delta * (u64)NS_PER_TICK); + if (delta < 1) { + /* Triggers in some wrap-around cases, but that's okay: + * we just end up with a shorter timeout. */ + st = processed_system_time + NS_PER_TICK; + } else if (((unsigned long)delta >> (BITS_PER_LONG-3)) != 0) { + /* Very long timeout means there is no pending timer. + * We indicate this to Xen by passing zero timeout. */ + st = 0; + } else { + st = processed_system_time + delta * (u64)NS_PER_TICK; + } } while (read_seqretry(&xtime_lock, seq)); return st; @@ -989,14 +995,15 @@ static void stop_hz_timer(void) smp_mb(); - /* Leave ourselves in 'tick mode' if rcu or softirq or timer pending. */ + /* Leave ourselves in tick mode if rcu or softirq or timer pending. */ if (rcu_needs_cpu(cpu) || local_softirq_pending() || (j = next_timer_interrupt(), time_before_eq(j, jiffies))) { cpu_clear(cpu, nohz_cpu_mask); j = jiffies + 1; } - BUG_ON(HYPERVISOR_set_timer_op(jiffies_to_st(j)) != 0); + if (HYPERVISOR_set_timer_op(jiffies_to_st(j)) != 0) + BUG(); } static void start_hz_timer(void) diff --git a/xen/common/schedule.c b/xen/common/schedule.c index cc9947e279..df9f9dcc3f 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -404,12 +404,15 @@ long do_set_timer_op(s_time_t timeout) * for timeouts wrapped negative, and for positive timeouts more than * about 13 days in the future (2^50ns). The correct fix is to trigger * an interrupt immediately (since Linux in fact has pending work to - * do in this situation). + * do in this situation). However, older guests also set a long timeout + * when they have *no* pending timers at all: setting an immediate + * timeout in this case can burn a lot of CPU. We therefore go for a + * reasonable middleground of triggering a timer event in 100ms. */ DPRINTK("Warning: huge timeout set by domain %d (vcpu %d):" " %"PRIx64"\n", v->domain->domain_id, v->vcpu_id, (uint64_t)timeout); - send_timer_event(v); + set_timer(&v->timer, NOW() + MILLISECS(100)); } else { -- 2.30.2